iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 22
1
Modern Web

Angular新手村學習筆記(2019)系列 第 22

Day22_Observable & RxJS in Angular

  • 分享至 

  • xImage
  •  

[S05E05] Observable & RxJS in Angular
https://www.youtube.com/watch?v=DuSs1zVVSko&list=PL9LUW6O9WZqgUMHwDsKQf3prtqVvjGZ6S&index=18

本集由Kevin大大講解

第1階段 文件導讀

導讀Angular官網文件裡的 Observables & RxJS

  1. https://angular.tw/guide/observables
    重點都在前幾集講過了
  2. https://angular.tw/guide/rx-library
    包含operators,(下一集)will保哥會講
  3. Observable in Angular 今天的主題
    https://angular.tw/guide/observables-in-angular
    在Angular裡面,用到RxJS實作的有
@Component({
  selector: 'async-observable-pipe',
  template: `<div>
                     <code> observable | async</code>:
    // 會去subscribe一個Observable或Promise^^^^^ 
       Time: {{ time | async }}</div>`
})
export class AsyncObservablePipeComponent {
  time = new Observable(observer =>
  ^^^^ 當time改變的時候,async pipe就會標記為需要cd(Change Detect)
    setInterval(() => observer.next(new Date().toString()), 1000)
  );
}
  • Router : 追蹤路由的記錄

Router events

import { Router, NavigationStart } from '@angular/router';
import { filter } from 'rxjs/operators';
 
@Component({
  selector: 'app-routable',
  templateUrl: './routable.component.html',
  styleUrls: ['./routable.component.css']
})
export class Routable1Component implements OnInit {
 
  navStart: Observable<NavigationStart>;
 
  constructor(private router: Router) {
    // Create a new Observable that publishes only the NavigationStart event
    this.navStart = router.events.pipe(
                           ^^^^^^ 不會停止
      filter(evt => evt instanceof NavigationStart)
    ) as Observable<NavigationStart>;
         ^^^^^^^^^^^^^^^^^^^^^^^^^^ NavigationStart是個Observable
  }
 
  ngOnInit() {
    this.navStart.subscribe(evt => console.log('Navigation Started!'));
                  ^^^^^^^^^ 取到NavigationStart就能subscribe
  }
}

ActivatedRoute,目前路由的位址

import { ActivatedRoute } from '@angular/router';
 
@Component({
  selector: 'app-routable',
  templateUrl: './routable.component.html',
  styleUrls: ['./routable.component.css']
})
export class Routable2Component implements OnInit {
  constructor(private activatedRoute: ActivatedRoute) {}
  // https://angular.tw/api/router/ActivatedRoute
  // ActivatedRoute 很多屬性都是Observable
  ngOnInit() {
    this.activatedRoute.url
                        ^^^ url: Observable<UrlSegment[]>
      .subscribe(url => console.log('The URL changed to: ' + url));
  }
}

// ActivatedRoute常用情境:
// 例用 params: Observable<Params>
// 在主檔取得id(主鍵),再進入明細表
  • Reactive forms
    https://angular.tw/api/forms/FormGroup
    看文件找有Observable的,有這2個:
    valueChanges: Observable<any>
    A FormControl 想跟 B FormControl 做連動的時候,可用valueChanges搭配operator

statusChanges: Observable<any>

訂閱可觀察的表單控制元件屬性是在元件類中觸發應用邏輯的途徑之一

import { FormGroup } from '@angular/forms';
 
@Component({
  selector: 'my-component',
  template: 'MyComponent Template'
})
export class MyComponent implements OnInit {
  nameChangeLog: string[] = [];
  heroForm: FormGroup;
 
  ngOnInit() {
    this.logNameChange();
  }
  logNameChange() {
    const nameControl = this.heroForm.get('name');
    nameControl.valueChanges.forEach(
      (value: string) => this.nameChangeLog.push(value)
    );
  }
}
  1. Practical Usage
    一些使用情境,自行參考
    https://angular.tw/guide/practical-observable-usage

第2階段 Kevin大大實戰

  1. app.component.ts
export class AppComponent {
    apiUrl = 'https://jsonplaceholder.typicode.com/posts';
    items$ = this.http.get(this.apiUrl);
    constructor(private http: HttpClient){}
  1. app.component.html
明明是同樣的items$
但如果寫2次,後端就會要2次,怎麼改善呢?
{{ items$ | async | json }}
{{ items$ | async | json }}

<div *ngIf="items$ | async as items">
            ^^^^^^^^^^^^^^ 當值取到時,會存放到items變數
    {{ items | json }}
    {{ items | json }}
<div>

來看Router的enableTracing: true功能

  1. app.module.ts 加入Router
RouterModule.forRoot(
    [
        { path: 'profile', component: ProfileComponent },
        { path: 'profile/:id', component: ProfileComponent },
                         ^^^^用ActivatedRoute的params或paramMap取
        { path: '', component: HomeComponent}
    ],
    {
        enableTracing: true
    }   ^^^^^^^^^^^^^^^^^^^ 這個也是用Observable來實作
  1. profile.component.ts
import { tap } from 'rxjs/operators';
export class ProfileComponent implements OnInit, OnDestroy {
    sub;
    
    constructor(
        private router: Router,
        private route: ActivatedRoute, // 使用方式差不多
        private http: HttpClient
        ){
        // 1. 示範 Router
        this.sub = this.router.events.subscribe(console.log);
                               ^^^^^^ 所以events應該是Observable或Promise
        // 查一下文件,https://angular.tw/api/router/Router
        // 所以是 events: Observable<Event>
        // An event stream for routing events in this NgModule.
        
        // 2. 示範 ActivatedRoute
        // 常見用法:利用ActivatedRoute.paramMap取得params中的id,再向後端要該id的資料
        this.route.paramMap
                   ^^^^^^^^ paramMap: Observable<ParamMap>
                   // https://angular.tw/api/router/ActivatedRoute#paramMap
            .pipe(mergeMap(params =>
                  ^^^^^^^^ https://ithelp.ithome.com.tw/articles/10188387
                  // https://rxjs-dev.firebaseapp.com/api/operators/mergeMap
                  // mergeMap 吐出來的應該也是一個 Observable
            this.http.get(`https://jsonplaceholder.typicode.com/users/${params.get('id')}`)))
                  
            .subscribe(data => console.log(data));
            
        this.route.paramMap.subscribe(params => console.log(params));
        
        // 3. tap operator
        // https://rxjs-dev.firebaseapp.com/api/operators/tap
        // tap<T>(nextOrObserver?: PartialObserver<T>): MonoTypeOperatorFunction<T>
        this.route.paramMap
            .pipe(tap(params => console.log(params.get('id'))))
            .subscribe(params => console.log(params));
    }
    
    ngOnDestroy(){
        this.sub.unsubscribe(); // 不確定this.router.events會不會自己中止
    }

上一篇
Day21_RxJS基本介紹-Subject
下一篇
Day23_RxJS 運算子全面解析(1/2)
系列文
Angular新手村學習筆記(2019)33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言